package com.example.impl;

import com.example.log.LogAnnotation;
import com.example.models.UserDTO;
import com.example.service.ApplicationRunnerService;
import com.example.service.AsyncService;
import com.example.service.UserDelegate;
import com.example.service.UserService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.TimeUnit;

/**
 * @Description
 * @Date 2021/7/9
 * @Created by Jonathan
 */
@Slf4j
@Service
public class UserDelegateImpl implements UserDelegate {

    @Resource
    private UserService userService;

    @Resource
    ApplicationRunnerService applicationRunnerService;

    @Resource
    private AsyncService asyncService;


    /**
     * 模拟死锁
     */
    @Override
    @LogAnnotation
    public void updateDataWithDeadLock() {
        new Thread(() -> {
            try {
                userService.updateData1();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }, "t1").start();

        new Thread(() -> {
            try {
                userService.updateData2();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }, "t2").start();
    }

    @Override
    public void updateDataWithoutDeadLock() {
        new Thread(() -> {
            try {
                userService.updateData3();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }, "t3").start();

        new Thread(() -> {
            try {
                userService.updateData4();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }, "t4").start();
    }

    @Override
    public void updateData() {
        new Thread(() -> {
            try {
                userService.updateData5();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }, "t5").start();

        new Thread(() -> {
            try {
                userService.updateData6();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }, "t6").start();
    }

    @Override
    public void cacheAsideProblem() {
        CountDownLatch latch = new CountDownLatch(1);
        new Thread(() -> {
            log.info("先调用一次，让缓存里面有值。");
            userService.getUser("465");
            latch.countDown();
        }).start();
        try {
            latch.await();
            log.info("latch.wait() 执行了。。。");
            TimeUnit.SECONDS.sleep(20);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        // 模拟两请求
        userService.cacheAsideProblem();
    }

    @Override
    public void deadLockDemo() {
        CountDownLatch latch = new CountDownLatch(20000);
        long start = System.currentTimeMillis();
        for (int i = 0; i < 20000; i++) {
            new Thread(() -> {
                userService.updateData0();
                latch.countDown();
            }, "thread-" + i).start();
        }
        try {
            latch.await();
            log.info("cost:{} ms", (System.currentTimeMillis() - start));
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }


    @Override
    @LogAnnotation
    public UserDTO getUserById(String id) {
        applicationRunnerService.test();
        asyncService.test();
        return userService.getUserById(id);
    }


    /**
     * 演示事务@Transactional失效的情况
     */
    @Override
    @LogAnnotation
    public void insert1() {
        userService.insert1();
    }

    /**
     * 演示事务@Transactional失效的情况
     */
    @Override
    public void insert2() {
        userService.insert2();
    }
}
